"""
Original GCR-NCCL Builder Implementation.

This builder wraps the existing build.sh script for the original GCR framework.
"""

import os
import subprocess
import time
import logging
from pathlib import Path
from typing import Dict, List, Optional, Any

from gcr_solver_manager.extensions.base_builder import (
    BuilderInterface, BuildConfig, BuildResult, BuildDependencyResult
)

logger = logging.getLogger(__name__)


class OriginalGCRBuilder(BuilderInterface):
    """Builder for Original GCR-NCCL framework."""
    
    def __init__(self, source_dir: Path):
        """Initialize builder with source directory."""
        self.source_dir = source_dir
        self.build_script = source_dir / "scripts" / "build.sh"
    
    def check_dependencies(self) -> BuildDependencyResult:
        """Check if required dependencies are available."""
        missing_deps = []
        version_info = {}
        
        try:
            # Check for MPI
            result = subprocess.run(['mpicc', '--version'], capture_output=True, text=True, timeout=10)
            if result.returncode == 0:
                version_info['mpi'] = result.stdout.split('\n')[0]
            else:
                missing_deps.append('mpi')
            
            # Check for CUDA (if GPU support needed)
            result = subprocess.run(['nvcc', '--version'], capture_output=True, text=True, timeout=10)
            if result.returncode == 0:
                version_info['cuda'] = result.stdout.split('\n')[-2] if result.stdout else 'unknown'
            else:
                missing_deps.append('cuda')
            
            # Check for CMake
            result = subprocess.run(['cmake', '--version'], capture_output=True, text=True, timeout=10)
            if result.returncode == 0:
                version_info['cmake'] = result.stdout.split('\n')[0]
            else:
                missing_deps.append('cmake')
            
            # Check if build script exists
            if not self.build_script.exists():
                missing_deps.append('build_script')
            
            satisfied = len(missing_deps) == 0
            
            return BuildDependencyResult(
                satisfied=satisfied,
                missing_dependencies=missing_deps,
                version_info=version_info,
                error_message=None if satisfied else f"Missing dependencies: {', '.join(missing_deps)}"
            )
            
        except Exception as e:
            return BuildDependencyResult(
                satisfied=False,
                missing_dependencies=['unknown'],
                version_info={},
                error_message=f"Dependency check failed: {e}"
            )
    
    def build(self, config: BuildConfig) -> BuildResult:
        """Perform framework-specific build operations."""
        start_time = time.time()
        
        try:
            # Prepare build command using existing build.sh script
            cmd = [str(self.build_script)]
            
            # Configure GPU backend
            if config.gpu_backend == 'cuda':
                cmd.extend(['--gpu', 'cuda'])
            elif config.gpu_backend == 'hip':
                cmd.extend(['--gpu', 'hip'])
            else:
                cmd.extend(['--gpu', 'cpu'])
            
            # Add debug flag
            if config.debug_mode:
                cmd.append('--debug')
            
            # Add clean build flag
            if config.clean_build:
                cmd.append('--clean')
            
            # Add parallel jobs
            cmd.extend(['--jobs', str(config.parallel_jobs)])
            
            # Add any extra options
            for key, value in config.extra_options.items():
                if key == 'solver':
                    cmd.extend(['--solver', str(value)])
                elif key == 'resolution':
                    cmd.extend(['--resolution', str(value)])
            
            logger.info(f"Building with command: {' '.join(cmd)}")
            
            # Execute build
            result = subprocess.run(
                cmd,
                cwd=self.source_dir,
                capture_output=True,
                text=True,
                timeout=1800  # 30 minutes timeout
            )
            
            duration = time.time() - start_time
            
            # Determine binary path
            binary_path = self._get_built_binary_path(config)
            
            success = result.returncode == 0 and (binary_path is None or binary_path.exists())
            
            build_result = BuildResult(
                success=success,
                binary_path=binary_path,
                build_log=f"Command: {' '.join(cmd)}\nSTDOUT:\n{result.stdout}\nSTDERR:\n{result.stderr}",
                duration=duration,
                error_message=None if success else f"Build failed with exit code {result.returncode}",
                cmake_args=[],  # build.sh handles CMake internally
                make_args=[]    # build.sh handles Make internally
            )
            
            logger.info(f"Build completed in {duration:.1f}s, success={success}")
            return build_result
            
        except subprocess.TimeoutExpired:
            return BuildResult(
                success=False,
                binary_path=None,
                build_log="Build timed out after 30 minutes",
                duration=time.time() - start_time,
                error_message="Build timeout"
            )
        except Exception as e:
            return BuildResult(
                success=False,
                binary_path=None,
                build_log=f"Build failed with exception: {e}",
                duration=time.time() - start_time,
                error_message=str(e)
            )
    
    def clean(self, config: BuildConfig) -> bool:
        """Clean build artifacts."""
        try:
            # Use build.sh with clean flag
            cmd = [str(self.build_script), '--clean']
            
            result = subprocess.run(
                cmd,
                cwd=self.source_dir,
                capture_output=True,
                text=True,
                timeout=300  # 5 minutes timeout
            )
            
            return result.returncode == 0
            
        except Exception as e:
            logger.error(f"Clean failed: {e}")
            return False
    
    def get_binary_path(self, config: BuildConfig) -> Optional[Path]:
        """Get path to built binary."""
        return self._get_built_binary_path(config)
    
    def _get_built_binary_path(self, config: BuildConfig) -> Optional[Path]:
        """Determine the expected binary path based on configuration."""
        build_dir = self.source_dir / "build"
        
        # Build binary name based on configuration
        binary_name = "main"
        
        if config.gpu_backend == 'cuda':
            binary_name += "-cuda-nccl-ca"
        elif config.gpu_backend == 'hip':
            binary_name += "-hip-rccl-ca"
        else:
            binary_name += "-cpu"
        
        if config.debug_mode:
            binary_name += "-debug"
        
        binary_name += ".exe"
        
        binary_path = build_dir / binary_name
        return binary_path if binary_path.exists() else None
    
    def install_dependencies(self) -> bool:
        """Install missing dependencies (not implemented for original GCR)."""
        logger.warning("Dependency installation not implemented for original GCR extension")
        return False